package net.borderwars.userserver;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.*;

/**
 * @author ehubbard
 *         Date: May 5, 2006
 *         Time: 11:21:58 AM
 */
public class Attachment {
    private ClientConnection clientConnection;

    public SocketChannel getSocket() {
        return socket;
    }

    private SocketChannel socket;

    public void setClientConnection(final ClientConnection cc) {
        this.clientConnection = cc;
    }

    public ClientConnection getClientConnection() {
        return clientConnection;
    }

    public enum ReadState {
        WAITSIZE, WAITOBJECT
    }

    private final Queue<ByteBuffer> outbound = new PriorityQueue<ByteBuffer>();

    ReadState currentState = ReadState.WAITSIZE;
    ByteBuffer readBuffer = ByteBuffer.allocate(4000);
    DataInputStream dis = null;
    ByteBufferInputStream bbis = null;
    int totalBytesRead = 0;
    int nextSize = 4;

    public Attachment(SocketChannel s) {
        bbis = new ByteBufferInputStream();
        dis = new DataInputStream(bbis);
        this.socket = s;
    }

    long bytesRead = 0;
    long readCount = 0;

    public List<Object> read(final SelectionKey sk, final SocketChannel sc) throws IOException, ClassNotFoundException {
        ArrayList<Object> readResults = new ArrayList<Object>();
        readBuffer.position(0);
        int rtn = 0; // read in however many bytes are available
        try {
            rtn = sc.read(readBuffer);
            if (rtn == -1) {
                Server.log.info("Client lost connection " + sc.socket().getRemoteSocketAddress());
                sk.attach(null); // remove our attachment from teh selection key
                sc.close();
                return (Collections.EMPTY_LIST);
            }
        }
        catch (IOException e) {
            // uh oh.. read error.. disconnect this bad boy!
            Server.log.info("Client lost connection " + sc.socket().getRemoteSocketAddress());
            sk.attach(null); // remove our attachment from teh selection key
            sc.close();
            return (Collections.EMPTY_LIST);
        }
        readBuffer.position(0);

        recordAvgReadSize(rtn);
        printAvgReadSize();

        byte data[] = new byte[rtn];
        readBuffer.get(data, 0, rtn); // grab out the bytes from the buffer

        bbis.add(data); // stick them on our happy go lucky Stream

        while (bbis.available() >= nextSize) {
            if (currentState.equals(ReadState.WAITSIZE)) { // if we are waiting for a size object
                nextSize = dis.readInt();
                currentState = ReadState.WAITOBJECT;

            } else if (currentState.equals(ReadState.WAITOBJECT)) {
                byte currentObject[] = new byte[nextSize];
                //noinspection ResultOfMethodCallIgnored
                dis.read(currentObject);
                ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(currentObject));
                readResults.add(ois.readObject());
                currentState = ReadState.WAITSIZE;
                nextSize = 4;
            }
        }
        return (readResults);
    }

    private void printAvgReadSize() {
        if (readCount % 3 == 0) { // only print every 10 reads
            long avg = bytesRead / readCount;
            Server.log.info("Average read is " + avg + "bytes");
        }

    }

    private void recordAvgReadSize(final int rtn) {
        bytesRead += rtn;
        readCount++;
    }

}
